package game;

import java.util.ArrayList;


/** This class represents a 'move' in a game. The move is simply represented by two integers: the row and
    the column where the player puts the marker. In addition, the <code>OthelloAction</code> has a field
    where the estimated value of the move can be stored during computations.

 * @author Henrik Bj&ouml;rklund
 */

public class OthelloAction{

	/** The row where the marker is placed. */
	protected int row = -1;

	/** The column where the marker is placed. */
	protected int column = -1;

	/** The estimated value of the move. */
	protected int value = 0;

	/** True if the player has to pass, i.e., if there is no legal move. */
	protected boolean pass = false;

	/** Creates a new <code>OthelloAction</code> with row <code>r</code>, column <code>c</code>, and
	value 0. 
	 */
	public OthelloAction(int r, int c){
		row = r;
		column = c;
		value = 0;
	}

	/** Sets the estimated value of the move. */
	public void setValue(int v){
		value = v;
	}

	/** Returns the estimated value of the move. */
	public int getValue(){
		return value;
	}

	/** Sets the column where the marker is to be placed. */
	public void setColumn(int c){
		column = c;
	}

	/** Returns the column where the marker is to be placed. */
	public int getColumn(){
		return column;
	}

	/** Sets the row where the marker is to be placed. */
	public void setRow(int r){
		row = r;
	}

	/** Returns the row where the marker is to be placed. */
	public int getRow(){
		return row;
	}

	/** Sets the boolean that indicates whether this is a pass move. This should only be
	true if there are no legal moves. */
	public void setPassMove(boolean b){
		pass = b;
	}

	/** Returns true if this is a pass move, indicating that the player has no legal moves.
	Otherwise returns false. */
	public boolean isPassMove(){
		return pass;
	}

	/**
	 * Apply changes to the board when a move is done
	 * @param position
	 * @return
	 */
	public AbstractOthelloPosition apply(AbstractOthelloPosition position) {
		char playerColor = (position.playerToMove) ? 'W' : 'B';
		char opponentColor = (position.playerToMove) ? 'B' : 'W';
		position.board[row][column] = playerColor;
		applyLineChange(row, column, playerColor, opponentColor, position);
		applyColumnChange(row, column, playerColor, opponentColor, position);
		applyDiagChange(row, column, playerColor, opponentColor, position);
		return position;
	}

	/**
	 * Apply changes for board lines
	 * @param r row index of the beginning of the move
	 * @param c column index of the beginning of the move
	 * @param playerColor player's color
	 * @param opponentColor opponent's color
	 * @param position current Othello position
	 */
	private void applyLineChange(int r, int c, char playerColor, char opponentColor, AbstractOthelloPosition position){
		ArrayList<Integer> toChange = new ArrayList<Integer>();
		int j = c - 1;
		int k = 1;
		boolean hasPiece = false;
		while(j >= 1 && !hasPiece && position.board[r][j] != 'E'){
			if(position.board[r][j] == playerColor){
				hasPiece = true;
			}
			toChange.add(k);
			k++;
			j--;
		}
		if(hasPiece){
			for(int n = 0; n < toChange.size(); n++){
				position.board[r][c - toChange.get(n)] = playerColor;
			}
		}
		hasPiece = false;
		j = c + 1;
		k = 1;
		toChange.clear();
		while(j <= AbstractOthelloPosition.BOARD_SIZE && !hasPiece && position.board[r][j] != 'E'){
			if(position.board[r][j] == playerColor){
				hasPiece = true;
			}
			toChange.add(k);
			k++;
			j++;
		}
		if(hasPiece){
			for(int n = 0; n < toChange.size(); n++){
				position.board[r][c + toChange.get(n)] = playerColor;
			}
		}
	}
	
	/**
	 * Apply changes for board columns
	 * @param r row index of the beginning of the move
	 * @param c column index of the beginning of the move
	 * @param playerColor player's color
	 * @param opponentColor opponent's color
	 * @param position current Othello position
	 */
	private void applyColumnChange(int r, int c, char playerColor, char opponentColor, AbstractOthelloPosition position){
		ArrayList<Integer> toChange = new ArrayList<Integer>();
		int i = r - 1;
		int k = 1;
		boolean hasPiece = false;
		while(i >= 1 && !hasPiece && position.board[i][c] != 'E'){
			if(position.board[i][c] == playerColor){
				hasPiece = true;
			}
			toChange.add(k);
			k++;
			i--;
		}
		if(hasPiece){
			for(int n = 0; n < toChange.size(); n++){
				position.board[r - toChange.get(n)][c] = playerColor;
			}
		}
		hasPiece = false;
		i = r + 1;
		k = 1;
		toChange.clear();
		while(i <= AbstractOthelloPosition.BOARD_SIZE && !hasPiece && position.board[i][c] != 'E'){
			if(position.board[i][c] == playerColor){
				hasPiece = true;
			}
			toChange.add(k);
			k++;
			i++;
		}
		if(hasPiece){
			for(int n = 0; n < toChange.size(); n++){
				position.board[r + toChange.get(n)][c] = playerColor;
			}
		}
	}
	
	/**
	 * Apply changes for board diagonals
	 * @param r row index of the beginning of the move
	 * @param c column index of the beginning of the move
	 * @param playerColor player's color
	 * @param opponentColor opponent's color
	 * @param position current Othello position
	 */
	private void applyDiagChange(int r, int c, char playerColor, char opponentColor, AbstractOthelloPosition position){
		ArrayList<Integer> toChange = new ArrayList<Integer>();
		boolean hasPiece = false;
		int i = r + 1;
		int j = c + 1;
		int k = 1;
		while(i <= AbstractOthelloPosition.BOARD_SIZE && j <= AbstractOthelloPosition.BOARD_SIZE && !hasPiece && position.board[i][j] != 'E'){
			if(position.board[i][j] == playerColor){
				hasPiece = true;
			}
				toChange.add(k);
				i++;
				j++;
				k++;
		}
		if(hasPiece){
			for(int n = 0; n < toChange.size(); n++){
				position.board[r + toChange.get(n)][c + toChange.get(n)] = playerColor;
			}
		}
		hasPiece = false;
		i = r + 1;
		j = c - 1;
		k = 1;
		toChange.clear();
		while(i <= AbstractOthelloPosition.BOARD_SIZE && j >= 1 && !hasPiece && position.board[i][j] != 'E'){
			if(position.board[i][j] == playerColor){
				hasPiece = true;
			}
			toChange.add(k);
			i++;
			j--;
			k++;
		}
		if(hasPiece){
			for(int n = 0; n < toChange.size(); n++){
				position.board[r + toChange.get(n)][c - toChange.get(n)] = playerColor;
			}
		}
		hasPiece = false;
		i = r - 1;
		j = c + 1;
		k = 1;
		toChange.clear();
		while(i >= 1 && j <= AbstractOthelloPosition.BOARD_SIZE && !hasPiece && position.board[i][j] != 'E'){
			if(position.board[i][j] == playerColor){
				hasPiece = true;
			}
			toChange.add(k);
			i--;
			j++;
			k++;
		}
		if(hasPiece){
			for(int n = 0; n < toChange.size(); n++){
				position.board[r - toChange.get(n)][c + toChange.get(n)] = playerColor;
			}
		}
		hasPiece = false;
		i = r - 1;
		j = c - 1;
		k = 1;
		toChange.clear();
		while(i >= 1 && j >= 1 && !hasPiece && position.board[i][j] != 'E'){
			if(position.board[i][j] == playerColor){
				hasPiece = true;
			}
			toChange.add(k);
			i--;
			j--;
			k++;
		}
		if(hasPiece){
			for(int n = 0; n < toChange.size(); n++){
				position.board[r - toChange.get(n)][c - toChange.get(n)] = playerColor;
			}
		}
		
	}
	
	/**
	 * Create the string which is writting to the mediator
	 * @return
	 */
	public String sendToMediator(){
		String str = "";
		if(isPassMove()){
			str = "pass";
		}else{
			str = "(" + getRow() + "," + getColumn() + ")";
		}
		return str;
	}
	
	@Override
	public String toString() {
		return "OthelloAction [row=" + row + ", column=" + column + ", value="
				+ value + ", pass=" + pass + "]";
	}


}